import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { BuildThemeService } from '../service/build-theme.service';
import { LoadingService } from './loading.service';
import { BuilderResult } from '../models/builder-result';
import { ExportedItem } from '../models/exported-item';
import { MetaItem, MetaValueChange } from '../models/meta-item';
import { Theme, ThemeConfig } from '../models/theme';
import { Metadata } from '../models/metadata';
import { ThemeRouteChangeService } from './theme-route-change.service';
import { ThemeExtendCSSService } from './theme-extend-css.service';

@Injectable({
    providedIn: 'root'
})
export class MetadataService {
    // 修改的变量的合集
    private modifiedMetaCollection: ExportedItem[] = [];

    // 修改的变量类型是否快速配置
    private modifiedVariableTypeIsRapid = false;

    private metadata: Metadata;

    // 标记主题的赋值之后的原始值
    private originalValueMetadata: MetaItem[];

    theme: Theme;

    css = new BehaviorSubject<{ css: string; theme: Theme }>({ css: '', theme: null });

    forceRebuild = false;

    globalBuildNumber = 0;

    constructor(
        private themeBuilder: BuildThemeService,
        private loading: LoadingService,
        private themeRouteChageSer: ThemeRouteChangeService,
        private extendCSSSer: ThemeExtendCSSService
    ) {
        this.theme = this.themeRouteChageSer.getDefaultTheme();
        // 生成主题
        this.build();

        this.themeRouteChageSer.getUrlChange().subscribe((url) => {
            const urlParts = url.split('/');
            const themeName = urlParts[0];
            const colorScheme = urlParts[1];
            if (themeName && colorScheme) {
                if (this.theme.name !== themeName || this.theme.colorScheme !== colorScheme) {
                    this.theme = { name: themeName, colorScheme };
                    // 清空已存的修改
                    this.clearModifiedDataCache();
                    this.build();
                }
            }
        });
    }

    clearModifiedDataCache(): void {
        this.modifiedMetaCollection = [];
        this.modifiedVariableTypeIsRapid = false;
    }

    /**
     * 如果已有元数据就按照当前的元数据取，
     * 如果没有元数据，就调用接口获取
     */
    private getMetadata(): Promise<Metadata> {
        if (this.metadata) {
            return Promise.resolve(this.metadata);
        }

        return this.themeBuilder.getMetadata().then((metadata) => {
            if (!this.metadata) this.metadata = metadata;
            return metadata;
        });
    }

    /**
     * 返回对应主题对下的变量定义
     */
    getData(): Promise<MetaItem[]> {
        const promiseMetadata = this.getMetadata();

        return promiseMetadata.then((metadata) => {
            return metadata[this.theme.name];
        });
    }

    getDataItemByKey(key: string): Promise<MetaItem> {
        return this.getData().then((data) => {
            return data.find((item) => item.Key === key);
        });
    }

    /**
     * 重置所有变量
     */
    resetVariables(): void {
        this.clearModifiedDataCache();
        const metadataStr = JSON.stringify(this.originalValueMetadata);
        this.metadata[this.theme.name] = JSON.parse(metadataStr);
        this.css.next({ css: '', theme: this.theme });
    }

    /**
     * 更新变量值
     * @param e
     * @param key
     * {changeValue:e,controlKey:key,variableType:this.variableType}
     */
    updateSingleVariable(metaChangeObj: MetaValueChange): void {
        this.getDataItemByKey(metaChangeObj.controlKey).then((dataItem) => {
            if (dataItem.Value === undefined) {
                return;
            }
            if (dataItem.Value === metaChangeObj.changeValue) {
                return;
            }
            // #333 和#333333是否相等的排除
            if (dataItem.Type === 'color') {
                const tColor = dataItem.Value.replace('#', '');
                if (dataItem.Value + tColor === metaChangeObj.changeValue) {
                    return;
                }
            }
            dataItem.Value = metaChangeObj.changeValue;
            if (metaChangeObj.variableType === 'rapidSettings') {
                this.modifiedVariableTypeIsRapid = true;
            }
            this.modifiedMetaCollection = this.modifiedMetaCollection.filter((item) => item.key !== dataItem.Key);
            this.modifiedMetaCollection.push({ key: dataItem.Key, value: dataItem.Value });
        });
    }

    private conformThemeName(themeName): Theme {
        let newThemeInfo: Theme = new Theme();
        switch (themeName) {
        case 'framework':
            newThemeInfo.name = themeName;
            newThemeInfo.colorScheme = this.themeRouteChageSer.getThemeColor();
            break;
        default:
            newThemeInfo = this.theme;
        }
        return newThemeInfo;
    }

    /**
     * 多个主题同时被生成
     * framework框架主题和farris主题（默认主题）
     */
    buildAll(): Promise<Array<BuilderResult>> {
        const allThemeBuilded = [];
        this.forceRebuild = true;
        ['framework', ''].forEach((item) => {
            allThemeBuilded.push(this.build(item));
        });
        return new Promise((resolve, reject) => {
            Promise.all(allThemeBuilded)
                .then((resArray) => {
                    this.forceRebuild = false;
                    resolve(resArray);
                })
                .catch((rejArray) => {
                    this.forceRebuild = false;
                    reject(rejArray);
                });
        });
    }

    /**
     * 获取变量集合
     */
    private getvariableCollection(themeInfo) {
        const variableRapidCollection: ExportedItem[] = [];
        if (this.modifiedMetaCollection.length > 0 && this.modifiedVariableTypeIsRapid) {
            //当有基础变量的变更时候，追加一个变量的修改
            variableRapidCollection.push({
                key: '$variable-type',
                value: 'rapidSettings'
            });
        }
        // 默认手写CSS是针对farris主题扩展，如果当前主题不是farris，则不追加这个变量
        if (themeInfo && themeInfo.name === 'farris') {
            variableRapidCollection.push({
                key: '$extend-css',
                value: this.extendCSSSer.getCSS()
            });
        }
        return variableRapidCollection.concat(...this.modifiedMetaCollection);
    }

    /**
     * 生成主题
     *
     * 快速配置中：
     * 1、farris和framework共用变量
     */
    build(themeName = ''): Promise<BuilderResult> {
        this.loading.show();
        const currentTheme = this.conformThemeName(themeName);
        // 获取当前主题的信息
        const buildResult = this.themeBuilder.buildTheme(currentTheme, {
            makeSwatch: false,
            items: this.getvariableCollection(currentTheme),
            widgets: [],
            noClean: true
        });

        const savedBuildNumber = ++this.globalBuildNumber;

        return buildResult.then((result) => {
            this.loading.hide();
            /**
             * result的结构
             *  {
             *  compiledMetadata: {'$base-accent':对象}
             *  css:"生成的css代码",
             *  swatchSelector:null,
             *  unusedWidgets:[],未使用的组件
             *  version:"21.2.3",
             *  widgets:["box","responsivebox"..]包含的组件
             * }
             *
             */
            if (!this.forceRebuild && savedBuildNumber !== this.globalBuildNumber) return;

            const itemPromises = [];
            // 处理变量的值，此处返回的变量对应的是个 [object object]
            Object.keys(result.compiledMetadata).forEach((dataKey) => {
                if (Object.prototype.hasOwnProperty.call(result.compiledMetadata, dataKey)) {
                    itemPromises.push(this.getDataItemByKey(dataKey));
                }
            });
            // itemPromises 存储的都是异步对象，等待结果然后赋值
            return Promise.all(itemPromises).then((resolveItems) => {
                /**resolveItems 开始结构
                 * {
                 *   Key:"$base-accent",
                 *   Name:"10. Accent color",
                 *   Type:"color"
                 * }
                 * ....
                 */
                resolveItems.forEach((item) => {
                    if (item) {
                        item.Value = result.compiledMetadata[item.Key];
                    }
                });
                /**
                 * resolveItems 结束之后结构
                 * {
                 *   Key:"$base-accent",
                 *   Name:"10. Accent color",
                 *   Type:"color",
                 *   Value:"[object object]"
                 * }
                 * ....
                 */
                // 记录当前的元数据
                if (this.modifiedMetaCollection.length === 0) {
                    //待替换
                    //避免对象的修改影响原值，此处用克隆的方式
                    const metadataStr = JSON.stringify(this.metadata[currentTheme.name]);
                    this.originalValueMetadata = JSON.parse(metadataStr);
                }
                // 记录当前主题的css
                this.css.next({ css: `//${currentTheme.name} ${currentTheme.colorScheme}  \n` + result.css, theme: currentTheme });
                return result;
            });
        });
    }

    /**
     * 获取基础变量的定义
     * themeNames是：多个主题的字符串：farris,framework
     * 返回的结果：
     * {farris:MetaItem[],framework:MetaItem[]}
     */
    getBaseParameters(themeNames: string): Promise<any> {
        return this.getMetadata().then((metadata) => {
            /**
             * items的结构
             * {
             *   Key:"$base-accent",
             *   Name:"10. Accent color",
             *   Type:"color",
             *   Value:"[object object]"
             * }
             * ....
             */
            const themeNamesArray = themeNames ? themeNames.split(',') : [this.theme.name];
            const result = {};
            themeNamesArray.forEach((themeName) => {
                result[themeName] = [];
                metadata[themeName].forEach((item) => {
                    const index = this.metadata.baseParameters[themeName].indexOf(item.Key.replace('$', '@'));
                    if (index >= 0) result[themeName][index] = item;
                });
            });
            /**
             * 基础参数或者说是基础变量
             * baseParameters中项["@base-accent","@base-text-color","@base-bg","@base-border-color","@base-border-radius"]
             * 给这些基础变量赋值，值的来源来自于主题的变量定义
             *
             */
            return result;
        });
    }

    getModifiedItems(): ExportedItem[] {
        return this.modifiedMetaCollection;
    }

    /**
     * 导出css时候调用此处
     * @param outColorScheme
     * @param swatch
     * @param widgets
     * @param assetsBasePath
     * @param removeExternalResources
     */
    export(themeName = ''): Promise<string> {
        return new Promise((resolve, reject): void => {
            const currentTheme = this.conformThemeName(themeName);
            // 按照配置信息重新生成一遍主题，并把css内容返回
            this.themeBuilder
                .buildTheme(currentTheme, {
                    makeSwatch: false,
                    items: this.getvariableCollection(currentTheme),
                    widgets: [],
                    noClean: false
                })
                .then(
                    (result) => {
                        resolve(result.css);
                    },
                    (error) => {
                        reject(error);
                    }
                );
        });
    }

    /**
     * 导入元数据
     * @param theme ：依赖的主题和颜色 比如{"name":"farris","colorScheme":"light"}
     * @param modifiedData 修改的变量
     */
    import(theme: Theme, modifiedData: ExportedItem[]): Promise<BuilderResult> {
        this.clearModifiedDataCache();
        this.theme = theme;
        this.modifiedMetaCollection = modifiedData;
        // 重新生成主题
        return this.build();
    }

    getVersion(): Promise<string> {
        if (this.metadata) {
            return Promise.resolve(this.metadata.version);
        }

        return this.getMetadata().then((metadata) => {
            if (!this.metadata) this.metadata = metadata;
            return metadata.version;
        });
    }

    /**
     * 获取所有主题的颜色列表
     * 返回结果是[{"themeId":1,"name":"farris","colorScheme":"light","text":"Light"},{}]
     */
    getThemes(): Promise<ThemeConfig[]> {
        if (this.metadata) {
            return Promise.resolve(this.metadata.themes);
        }

        return this.getMetadata().then((metadata) => {
            if (!this.metadata) this.metadata = metadata;
            return metadata.themes;
        });
    }

    /**
     * 获取当前主题
     */
    getCurrentTheme() {
        return this.theme;
    }
}
